﻿using System;
using Ewk.Math.ComputationTypes;

namespace Ewk.Math.Algebra.Algorithms.Matrices
{
    /// <summary>
    /// Defines a manipulator of a property of a matrix.
    /// </summary>
    /// <typeparam name="T">The element <see cref="Type"/> of the <see cref="Matrix{T}"/>.</typeparam>
    /// <typeparam name="TSubject">The type of the property that is manipulated.</typeparam>
    public interface IMatrixManipulations<T, out TSubject>
        where T : struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T>
    {
        /// <summary>
        /// Manipulate the property for this action.
        /// </summary>
        /// <param name="index1">The index of the first row.</param>
        /// <param name="index2">The index of the second row.</param>
        /// <returns>The value of the property after manipulation.</returns>
        TSubject SwapRows(int index1, int index2);

        /// <summary>
        /// Manipulate the property for this action.
        /// </summary>
        /// <param name="index1">The index of the first row.</param>
        /// <param name="index2">The index of the second row.</param>
        /// <returns>The value of the property after manipulation.</returns>
        TSubject SwapColumns(int index1, int index2);

        /// <summary>
        /// Manipulate the property for this action.
        /// </summary>
        /// <param name="value">The value that is used for the manipulation.</param>
        /// <returns>The value of the property after manipulation.</returns>
        TSubject Add(Computable<T> value);

        /// <summary>
        /// Manipulate the property for this action.
        /// </summary>
        /// <param name="matrix">The matrix that is used for the manipulation.</param>
        /// <returns>The value of the property after manipulation.</returns>
        TSubject Add(Matrix<T> matrix);

        /// <summary>
        /// Manipulate the property for this action.
        /// </summary>
        /// <param name="value">The value that is used for the manipulation.</param>
        /// <returns>The value of the property after manipulation.</returns>
        TSubject Subtract(Computable<T> value);

        /// <summary>
        /// Manipulate the property for this action.
        /// </summary>
        /// <param name="matrix">The matrix that is used for the manipulation.</param>
        /// <returns>The value of the property after manipulation.</returns>
        TSubject Subtract(Matrix<T> matrix);

        /// <summary>
        /// Manipulate the property for this action.
        /// </summary>
        /// <param name="value">The value that is used for the manipulation.</param>
        /// <returns>The value of the property after manipulation.</returns>
        TSubject Multiply(Computable<T> value);

        /// <summary>
        /// Manipulate the property for this action.
        /// </summary>
        /// <param name="matrix">The matrix that is used for the manipulation.</param>
        /// <returns>The value of the property after manipulation.</returns>
        TSubject Multiply(Matrix<T> matrix);

        /// <summary>
        /// Manipulate the property for this action.
        /// </summary>
        /// <param name="value">The value that is used for the manipulation.</param>
        /// <returns>The value of the property after manipulation.</returns>
        TSubject Divide(Computable<T> value);

        /// <summary>
        /// Manipulate the property for this action.
        /// </summary>
        /// <returns>The value of the property after manipulation.</returns>
        TSubject Transpose();

        /// <summary>
        /// Manipulate the property for this action.
        /// </summary>
        /// <returns>The value of the property after manipulation.</returns>
        TSubject Invert();

        /// <summary>
        /// Manipulate the property for this action.
        /// </summary>
        /// <returns>The value of the property after manipulation.</returns>
        TSubject Adjugate();
    }
}